/********************************************************/
/*	Author:		gong_libin			*/
/*	Date:		2014_08_13			*/
/*	File:		GtRmInet.c			*/
/********************************************************/

#include "GtGlobal.h"
#include <fcntl.h>
#include <ctype.h>
#include <getopt.h>
#include <signal.h>
#include <unistd.h>
#include <pthread.h>
#include <net/if.h>
#include <sys/un.h>
#include <sys/shm.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#define __FAVOR_BSD
#include <netinet/udp.h>
#include <netinet/tcp.h>
#include <net/ethernet.h>
#include <netpacket/packet.h>

void GtRiHttp(UCHAR* puszRecv, int iLength);
void GtRiGtpu(UCHAR* puszRecv, int iLength);
void GtRiGtpc(UCHAR* puszRecv, int iLength);
void GtRiRads(UCHAR* puszRecv, int iLength);
void GtRiPrint(UCHAR* puszRecv, int iLength);
int GtRiNetwork(UCHAR* puszRecv, int iLength, USHORT usBase);

int main(int argc, char* argv[])
{
	int iSocket = 0;
	int iLength = 0;
	int iOffset = 0;
	USHORT usPort = 0;
	char* pszEth = NULL;
	struct ifreq stIfreq;
	struct sockaddr_ll stAddr;
	UCHAR uszRecv[GT_KBYTES8] = { 0 };

	if (argc < 3) {
		GT_PRINT("Usage: %s eth port\n", argv[0]);
		return GT_SUCCESS;
	}
	else {
		usPort = atoi(argv[2]);
		pszEth = argv[1];
	}

	if (GT_FAILURE != (iSocket = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)))) {
		strcpy(stIfreq.ifr_name, pszEth);
		if (GT_SUCCESS == ioctl(iSocket, SIOCGIFINDEX, &stIfreq)) {
			stAddr.sll_family = PF_PACKET;
			stAddr.sll_protocol = htons(ETH_P_ALL);
			stAddr.sll_ifindex = stIfreq.ifr_ifindex;
			if (GT_SUCCESS == bind(iSocket, (struct sockaddr*)&stAddr, sizeof(stAddr))) {
				while ((iLength = recvfrom(iSocket, uszRecv, GT_KBYTES8, 0, NULL, NULL)) > 0) {
					if ((iOffset = GtRiNetwork(uszRecv, iLength, usPort)) > 0) {
						switch (usPort) {
							case 1813:
								GtRiRads(uszRecv + iOffset, iLength - iOffset);
								break;
							case 2152:
								GtRiGtpu(uszRecv + iOffset, iLength - iOffset);
								break;
							case 2123:
								GtRiGtpc(uszRecv + iOffset, iLength - iOffset);
								break;
							default:
								GtRiHttp(uszRecv + iOffset, iLength - iOffset);
								break;
						}
					}
					memset(uszRecv, '\0', GT_KBYTES8);
				}
			}
			else {
				GT_ERROR("%s\n", strerror(errno));
				close(iSocket);
			}
		}
		else {
			GT_ERROR("%s\n", strerror(errno));
			close(iSocket);
		}

		close(iSocket);
	}
	else {
		GT_ERROR("%s\n", strerror(errno));
	}

	return GT_SUCCESS;
}

int GtRiNetwork(UCHAR* puszRecv, int iLength, USHORT usBase)
{
	int iSize = 0;
	USHORT usPort = 0;
	struct ip* pstIP = NULL;
	struct udphdr* pstUdp = NULL;
	struct tcphdr* pstTcp = NULL;
	struct ether_header* pstEth = NULL;

	/* eth */
	pstEth = (struct ether_header*)puszRecv;
	iSize = sizeof(struct ether_header);

	/* ip */
	pstIP = (struct ip*)(puszRecv + iSize);
	iSize += pstIP->ip_hl * 4;

	switch (pstIP->ip_p) {
		case IPPROTO_TCP:
			pstTcp = (struct tcphdr*)((UCHAR*)pstIP + pstIP->ip_hl * 4);
			usPort = ntohs(pstTcp->th_dport);
			iSize += pstTcp->th_off * 4;
			break;
		case IPPROTO_UDP:
			pstUdp = (struct udphdr*)((UCHAR*)pstIP + pstIP->ip_hl * 4);
			usPort = ntohs(pstUdp->uh_dport);
			iSize += sizeof(struct udphdr);
			break;
		default:
			break;
	}

	if (usBase == usPort) {
		GT_PRINT("\nPacket: %d\n", iLength);
		GT_PRINT("SrcMac: %02x:%02x:%02x:%02x:%02x:%02x\t",
			pstEth->ether_shost[0], pstEth->ether_shost[1], pstEth->ether_shost[2],
			pstEth->ether_shost[3], pstEth->ether_shost[4], pstEth->ether_shost[5]);
		GT_PRINT("DstMac: %02x:%02x:%02x:%02x:%02x:%02x\t",
			pstEth->ether_dhost[0], pstEth->ether_dhost[1], pstEth->ether_dhost[2],
			pstEth->ether_dhost[3], pstEth->ether_dhost[4], pstEth->ether_dhost[5]);
		GT_PRINT("Type: 0x%04x\n", ntohs(pstEth->ether_type));
		GT_PRINT("SrcAddr: %s\t", (char*)inet_ntoa(pstIP->ip_src));
		GT_PRINT("DstAddr: %s\n", (char*)inet_ntoa(pstIP->ip_dst));
		if (NULL != pstTcp) {
			GT_PRINT("SrcPort: %d\t", ntohs(pstTcp->th_sport));
			GT_PRINT("DstPort: %d\n", ntohs(pstTcp->th_dport));
		}
		else if (NULL != pstUdp) {
			GT_PRINT("SrcPort: %d\t", ntohs(pstUdp->uh_sport));
			GT_PRINT("DstPort: %d\n", ntohs(pstUdp->uh_dport));
		}
		else {
			GT_PRINT("Error\n");
		}
	}
	else {
		iSize = 0;
	}

	return iSize;
}

void GtRiPrint(UCHAR* puszRecv, int iLength)
{
	int iCount = 0;

	GT_PRINT("Packet[%d]:", iLength);
	for (; iCount < iLength; iCount ++) {
		if (0 == iCount % sizeof(int)) {
			if (0 == iCount % (sizeof(int) * 2)) {
				GT_PRINT("\n");
			}
			else {
				GT_PRINT(" ");
			}
		}
		GT_PRINT("0x%02x ", *(puszRecv + iCount));
	}
	GT_PRINT("\n");

	return;
}

void GtRiHttp(UCHAR* puszRecv, int iLength)
{
	GT_PRINT("%s", (char*)puszRecv);

	return;
}

void GtRiGtpu(UCHAR* puszRecv, int iLength)
{
	GtRiPrint(puszRecv, iLength);

	return;
}

void GtRiGtpc(UCHAR* puszRecv, int iLength)
{
	GtRiPrint(puszRecv, iLength);

	return;
}

void GtRiRads(UCHAR* puszRecv, int iLength)
{
	GtRiPrint(puszRecv, iLength);

	return;
}
